package com.frskycockpit.activity;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
import android.widget.Toast;

import com.frskycockpit.FrskyCockpit;
import com.frskycockpit.R;
import com.frskycockpit.bluetooth.BluetoothSerial;
import com.frskycockpit.bluetooth.BluetoothSerialCallback;
import com.frskycockpit.fragment.SensorFragment;
import com.frskycockpit.log.LogData;
import com.frskycockpit.object.Sensor;

public class MainActivity extends FragmentActivity implements OnClickListener,
		BluetoothSerialCallback {
	TextView tv_statusBT = null;
	LinearLayout ll_statusBT = null;
	LinearLayout ll_statusRX = null;
	LinearLayout ll_statusTX = null;
	LinearLayout ll_statusLog = null;
	LinearLayout rl_main = null;
	TableLayout tl_main = null;

	boolean IMMERSIVE_MODE = false;
	private boolean doubleBackToExitPressedOnce = false;

	private ArrayList<SensorFragment> sensorFragmentArrayList = null;
	/**
	 * 
	 */
	BluetoothSerial mBluetoothSerial = null;

	/**
	 * 
	 */
	public static final int SIZE_TELEMETRY_FRAME = 11;
	public static final int START_STOP_TELEMETRY_FRAME = 0x7E;
	/**
	 * 
	 */
	private int nbCapteurOnScreen = 1;
	/**
	 * the current user frame we are working on. This is used to pass data
	 * between incomplete frames.
	 */
	private List<Integer> frSkyFrame = new ArrayList<Integer>(
			SIZE_TELEMETRY_FRAME);
	private LogData ld;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.d(FrskyCockpit.LOG_TAG, "onCreate");
		mBluetoothSerial = new BluetoothSerial(this, handler, this);
		setContentView(R.layout.activity_telemetry);
		tv_statusBT = (TextView) findViewById(R.id.tv_statusBT);
		ll_statusBT = (LinearLayout) findViewById(R.id.ll_statusBT);
		ll_statusRX = (LinearLayout) findViewById(R.id.ll_statusRX);
		ll_statusTX = (LinearLayout) findViewById(R.id.ll_statusTX);
		ll_statusLog = (LinearLayout) findViewById(R.id.ll_statusLog);
		//
		rl_main = (LinearLayout) findViewById(R.id.rl_main);
		rl_main.setOnClickListener(this);
		tl_main = (TableLayout) findViewById(R.id.tl_main);

		sensorFragmentArrayList = new ArrayList<SensorFragment>();
	}

	@Override
	protected void onResume() {
		super.onResume();
		Log.d(FrskyCockpit.LOG_TAG, "onResume");
		this.doubleBackToExitPressedOnce = false;
		refreshMainScreen();
		refreshStateBar();
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		Log.d(FrskyCockpit.LOG_TAG, "onSaveInstanceState");
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		Log.d(FrskyCockpit.LOG_TAG, "onConfigurationChanged");
		refreshMainScreen();
		refreshStateBar();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		if (mBluetoothSerial.isOpen()) {
			menu.findItem(R.id.action_connect_bt).setVisible(false);
			menu.findItem(R.id.action_disconnect_bt).setVisible(true);
		} else {
			menu.findItem(R.id.action_connect_bt).setVisible(true);
			menu.findItem(R.id.action_disconnect_bt).setVisible(false);
		}
		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		if (item.getItemId() == R.id.action_about) {
			AlertDialog.Builder builder = new AlertDialog.Builder(this);
			builder.setTitle(getString(R.string.app_name));
			builder.setMessage(((FrskyCockpit) getApplication()).getAbout())
					.setCancelable(false)
					.setPositiveButton("OK",
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog,
										int id) {
									dialog.cancel();
								}
							});
			AlertDialog alert = builder.create();
			alert.show();
		} else if (item.getItemId() == R.id.action_connect_bt) {
			if (mBluetoothSerial.findBT()) {
				Toast.makeText(this, "Not enable bluetooth adapter",
						Toast.LENGTH_LONG).show();
			}
		} else if (item.getItemId() == R.id.action_disconnect_bt) {
			if (mBluetoothSerial.closeBT()) {
				refreshStateBar();
			}
		} else if (item.getItemId() == R.id.action_parameter) {
			Intent intent = new Intent(getApplicationContext(),
					SettingsActivity.class);
			startActivity(intent);

		} else if (item.getItemId() == R.id.action_help) {
			Intent intent = new Intent(getApplicationContext(),
					HelpActivity.class);
			startActivity(intent);

		}
		return true;
	}

	@Override
	public void onClick(View v) {
		Log.d(FrskyCockpit.LOG_TAG, "onClick");
		if (v == rl_main) {
			if (!IMMERSIVE_MODE) {
				toggleFullscreen(true);
				IMMERSIVE_MODE = true;
			} else {
				toggleFullscreen(false);
				IMMERSIVE_MODE = false;
			}
		}
	}

	@Override
	public void onBackPressed() {
		if (doubleBackToExitPressedOnce) {
			super.onBackPressed();
			return;
		}
		this.doubleBackToExitPressedOnce = true;
		Toast.makeText(this, R.string.exit_press_back_twice_message,
				Toast.LENGTH_SHORT).show();
	}

	private void toggleFullscreen(boolean fullscreen) {
		Log.d(FrskyCockpit.LOG_TAG, "toggleFullscreen: " + fullscreen);
		WindowManager.LayoutParams attrs = getWindow().getAttributes();
		if (fullscreen) {
			attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
            if (getActionBar() != null)
                getActionBar().hide();
			getWindow()
					.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
			// iv_logdata.setImageResource(R.drawable.ic_green_start);
			if (ld == null)
				ld = new LogData(this);
			for (int i = 0; i < sensorFragmentArrayList.size(); i++) {
				sensorFragmentArrayList.get(i).showSpinner(false);
			}

		} else {
			attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
            if (getActionBar() != null)
                getActionBar().show();
			getWindow().clearFlags(
					WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
			// iv_logdata.setImageResource(R.drawable.ic_red_stop);
			ld = null;
			for (int i = 0; i < sensorFragmentArrayList.size(); i++) {
				sensorFragmentArrayList.get(i).showSpinner(true);
			}
		}
		getWindow().setAttributes(attrs);
	}

	// Head|Prim|Threshold Value|Greater|Alarm
	// Level|byte1|byte2|byte3|byte4|byte5|End Byte
	// 7E FE 62 94 61 CE 00 00 00 00 7E

	private final Handler handler = new Handler() {
		public void handleMessage(Message msg) {
			byte[] data = msg.getData().getByteArray("buffer");
			if ((null != data)) {
				// Log.d(FrskyTelemetry.LOG_TAG, "Data: " + bytesToHex(data));
				handleByteBuffer(data);
			}
		}
	};

	public void handleByteBuffer(byte[] buffer) {
		// init current byte
		int b;
		// iterate all bytes in buffer
		for (int i = 0; i < buffer.length; i++) {
			// use & 0xff to properly convert from byte to 0-255 int
			// value (java only knows signed bytes)
			b = buffer[i] & 0xff;
			// no decoding at this point, just parse the frames from this buffer
			// on start stop byte we need to pass alon the collected frame and
			// clean up so we can start collecting another frame
			if (b == START_STOP_TELEMETRY_FRAME) {
				// we already have content so we were working on a valid frame
				if (!frSkyFrame.isEmpty()) {
					// complete this frame with the stop bit
					frSkyFrame.add(b);
					// pass along
					handleFrame(frSkyFrame);
					// clean up
					frSkyFrame.clear();
				}
				// otherwise this is a start bit so just register
				else
					frSkyFrame.add(b);
			}
			// otherwise just add to the current frame were working on
			else {
				frSkyFrame.add(b);
			}
		}
	}

	/**
	 *
	 */
	public void handleFrame(List<Integer> frame) {
		if (frame == null)
			return;
		String str = "";
		for (int i = 0; i < frame.size(); i++) {
			str += Integer.toHexString(frame.get(i));
		}
		//Log.d(FrskyCockpit.LOG_TAG, "Data: " + str);

		if (frame.get(1) == 0xfe) {
            SensorFragment sf = getSensorByType(Sensor.SENSOR_TYPE_A1);
            if (sf != null)
                sf.refreshValue(frame.get(2));
            sf = getSensorByType(Sensor.SENSOR_TYPE_A2);
            if (sf != null)
                sf.refreshValue(frame.get(3));

			// sfA1.refreshValue(frame.get(2));
			// sfA2.refreshValue(frame.get(3));

			// Boolean activatedLog = PreferenceManager
			// .getDefaultSharedPreferences(this).getBoolean(
			// "activatedLog", false);
			// if (activatedLog && ld != null) {
			// String strLog = "";
			// if (isShowA1)
			// strLog += coefA1 + LogData.DELIMETER + name
			// + LogData.DELIMETER + unitee + LogData.DELIMETER
			// + nbDecA1 + LogData.DELIMETER + valueA1
			// + LogData.DELIMETER;
			// if (isShowA2)
			// strLog += coefA2 + LogData.DELIMETER + nameA2
			// + LogData.DELIMETER + uniteeA2 + LogData.DELIMETER
			// + nbDecA2 + LogData.DELIMETER + valueA2
			// + LogData.DELIMETER;
			// if (str.length() > 0)
			// ld.append(strLog);
			// }

			// ad1 = frame.get(2);
			// ad2 = frame.get(3);
			// rssirx = frame.get(4);
			// rssitx = (int) frame.get(5) / 2;
		}

	}

	@Override
	public void OnBluetoothSerialOpen() {
		refreshStateBar();
	}

	@Override
	public void OnBluetoothSerialClose() {
		refreshStateBar();
	}

	@Override
	public void OnBluetoothSerialRecievedData() {
		ll_statusRX.setBackgroundColor(Color.GREEN);
	}

	@Override
	public void OnBluetoothOpen() {
		refreshStateBar();
	}

	@Override
	public void OnBluetoothSerialNoRecievedData() {
		ll_statusRX.setBackgroundColor(Color.RED);
	}
	/**
	 * refresh state bar
	 */
	private void refreshStateBar() {
		ll_statusBT.setBackgroundColor(Color.RED);
		ll_statusRX.setBackgroundColor(Color.RED);
		ll_statusTX.setBackgroundColor(Color.RED);
		if (mBluetoothSerial != null) {
			if (mBluetoothSerial.isEnable())
				ll_statusBT.setBackgroundColor(Color.GREEN);
			if (mBluetoothSerial.isOpen())
				ll_statusTX.setBackgroundColor(Color.GREEN);
		}
	}

	/**
	 * refresh the main screen with settings
	 */
	private void refreshMainScreen() {
		nbCapteurOnScreen = Integer.parseInt(PreferenceManager
				.getDefaultSharedPreferences(this).getString(
						"nbSensorPreference", "3"));

		tl_main.removeAllViews();
		sensorFragmentArrayList.clear();
		int sensorId = 1;
		int start = 0;
		int nbrow = 0;
		if ((nbCapteurOnScreen % 2) != 0) {
			TableRow row = new TableRow(this);
			row.setId(0x101 + nbrow);
			row.setLayoutParams(new TableRow.LayoutParams(
					TableRow.LayoutParams.MATCH_PARENT,
					TableRow.LayoutParams.MATCH_PARENT));
			SensorFragment sf = SensorFragment.newInstance(sensorId);
			getSupportFragmentManager().beginTransaction()
					.add(0x101 + nbrow, sf).commit();
			sensorFragmentArrayList.add(sf);
			tl_main.addView(row, new TableLayout.LayoutParams(
					TableLayout.LayoutParams.MATCH_PARENT, 0, 1.0f));
			start++;
			sensorId++;
		}
		TableRow row = new TableRow(this);
		int nbAdd = 0;
		for (int i = start; i < nbCapteurOnScreen; i++) {
			Log.d(FrskyCockpit.LOG_TAG, "i: " + i + " " + (i % 2));
			if (nbAdd == 0) {
				nbrow++;
				row = new TableRow(this);
				row.setId(0x101 + nbrow);
				row.setLayoutParams(new TableRow.LayoutParams(
						TableRow.LayoutParams.MATCH_PARENT,
						TableRow.LayoutParams.MATCH_PARENT));
				tl_main.addView(row, new TableLayout.LayoutParams(
						TableLayout.LayoutParams.MATCH_PARENT, 0, 1.0f));
			}
			//Sensor sensorA1 = Sensor.loadSensor(this, Sensor.SENSOR_TYPE_A1);
			SensorFragment sf = SensorFragment.newInstance(sensorId);
			getSupportFragmentManager().beginTransaction()
					.add(0x101 + nbrow, sf).commit();
			sensorFragmentArrayList.add(sf);
			nbAdd++;
			if (nbAdd == 2)
				nbAdd = 0;
			sensorId++;
		}
	}

    SensorFragment getSensorByType(String type){
        Log.d(FrskyCockpit.LOG_TAG, "Sensor type: " + type + " sensorFragmentArrayList.size: " +  sensorFragmentArrayList.size());
        for (int i =0; i < sensorFragmentArrayList.size(); i++) {
            SensorFragment sf = sensorFragmentArrayList.get(i);
            Sensor s = sf.getSensor();
            if (s != null) {
                Log.d(FrskyCockpit.LOG_TAG, "name: " + s.getName());
                if (s != null && s.getName().equals("name" + type)) {
                    Log.d(FrskyCockpit.LOG_TAG, "Find: name" + type);
                    return sf;
                }
            }
        }
        return null;
    }
}
